/**
 * 
 */
package com.huaqin.expression;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;

import com.huaqin.expression.BaseDataMeta.DataType;


/**
 * 操作符执行接口
 */
public interface IOperatorExecution {
	/**
	 * 执行操作符运算
	 * @param args 注意args中的参数由于是从栈中按LIFO顺序弹出的，所以必须从尾部倒着取数
	 * @return Constant 常量型的执行结果
	 * @throws IllegalExpressionException
	 */
	public Constant execute(Constant[] args) throws IllegalExpressionException;
	
	/**
	 * 验证操作符参数是否合法
	 * @param opPositin
	 * @param args 注意args中的参数由于是从栈中按LIFO顺序弹出的，所以必须从尾部倒着取数
	 * @return Constant 常量型的执行结果
	 * @throws IllegalExpressionException
	 */
	public Constant verify(int opPositin , BaseDataMeta[] args) throws IllegalExpressionException;
	
	
	/**
	 * 非法的表达式异常
	 */
	public class IllegalExpressionException extends Exception {
		
		/**
		 * 
		 */
		private static final long serialVersionUID = -382075370364295450L;
		
		/**
		 * 错误标识
		 */
		private String errorTokenText;
		/**
		 * 错误位置
		 */
		private int errorPosition = -1;

		public IllegalExpressionException(){
			super();
		}
		
		public IllegalExpressionException(String msg){
			super(msg);
		}
		
		public IllegalExpressionException(String msg , String errorTokenText ){
			super(msg);
			this.errorTokenText = errorTokenText;
		}
		
		public IllegalExpressionException(String msg , String errorTokenText , int errorPosition){
			super(msg);
			this.errorPosition = errorPosition;
			this.errorTokenText = errorTokenText;
		}	
		
		public String getErrorTokenText() {
			return errorTokenText;
		}
		public void setErrorTokenText(String errorTokenText) {
			this.errorTokenText = errorTokenText;
		}
		public int getErrorPosition() {
			return errorPosition;
		}
		public void setErrorPosition(int errorPosition) {
			this.errorPosition = errorPosition;
		}

		public String toString(){
			StringBuffer sb = new StringBuffer(this.getMessage());
			sb.append("\r\n处理对象：").append(errorTokenText);
			sb.append("\r\n处理位置：").append(errorPosition == -1 ? " unknow " : errorPosition);
			return sb.toString();
		}
	}
	
	/**
	 * 表达式操作符接口
	 * 操作符优先级数值越大，优先级越高
	 */
	public enum Operator{
		
		//逻辑与
		AND("&&" , 30 , 2),
		
		//逻辑或
		OR("||" , 20 , 2),
		
		;
		
		private static final Set<String> OP_RESERVE_WORD = new HashSet<String>();
		
		static{
			
			OP_RESERVE_WORD.add(AND.getToken());
			
			OP_RESERVE_WORD.add(OR.getToken());
		}
		
		private static final HashMap<Operator , IOperatorExecution> OP_EXEC_MAP 
						= new HashMap<Operator , IOperatorExecution>();
		
		static{
			OP_EXEC_MAP.put(AND, new Op_AND());
			OP_EXEC_MAP.put(OR, new Op_OR());	
		}

		/**
		 * 判断字符串是否是合法的操作符
		 * @param tokenText
		 * @return
		 */
		public static boolean isLegalOperatorToken(String tokenText){
			return OP_RESERVE_WORD.contains(tokenText);
		}
		
		private String token;
		
		private int priority;
		
		private int opType;
		
		Operator(String token , int priority , int opType){
			this.token = token;
			this.priority = priority;
			this.opType = opType;
		}
		
		/**
		 * 获取操作符的字符表示
		 * 如：+  - equals && ==
		 * @return String 操作符的字符形态
		 */
		public String getToken(){
			return this.token;
		}
		/**
		 * 获取操作符的优先级
		 * @return int 操作符优先级
		 */
		public int getPiority(){
			return this.priority;
		}

		/**
		 * 操作符类型
		 * 一元 ！
		 * 二元 && >=
		 * @return int 操作符类型（几元操作）
		 */
		public int getOpType(){
			return this.opType;
		}
		
		/**
		 * 执行操作，并返回结果Token
		 * @param args 注意args中的参数由于是从栈中按LIFO顺序弹出的，所以必须从尾部倒着取数
		 * @return Constant 常量型的执行结果
		 */
		public Constant execute(Constant[] args)throws IllegalExpressionException{
			
			IOperatorExecution opExec = OP_EXEC_MAP.get(this);
			if(opExec == null){
				throw new IllegalStateException("系统内部错误：找不到操作符对应的执行定义");
			}
			return opExec.execute(args);
		}
		
		/**
		 * 检查操作符和参数是否合法，是可执行的
		 * 如果合法，则返回含有执行结果类型的Token
		 * 如果不合法，则返回null
		 * @param opPositin 操作符位置
		 * @param args 注意args中的参数由于是从栈中按LIFO顺序弹出的，所以必须从尾部倒着取数
		 * @return Constant 常量型的执行结果
		 */
		public Constant verify(int opPositin , BaseDataMeta[] args)throws IllegalExpressionException{
			
			IOperatorExecution opExec = OP_EXEC_MAP.get(this);
			if(opExec == null){
				throw new IllegalStateException("系统内部错误：找不到操作符对应的执行定义");
			}
			return opExec.verify(opPositin, args);
		}

	}
	
	/**
	 * 逻辑与操作
	 */
	public class Op_AND implements IOperatorExecution {

		public static final Operator THIS_OPERATOR = Operator.AND;
		
		/* (non-Javadoc)
		 * @see com.huaqin.expression.op.IOperatorExecution#execute(com.huaqin.expression.ExpressionToken[])
		 */
		public Constant execute(Constant[] args) throws IllegalExpressionException {
			//参数校验
			if(args == null || args.length != 2){
				throw new IllegalArgumentException("操作符\"" + THIS_OPERATOR.getToken() + "操作缺少参数");
			}
			Constant first = args[1];
			if(null == first || null == first.getDataValue()){
				//抛NULL异常
				throw new NullPointerException("操作符\"" + THIS_OPERATOR.getToken() + "\"参数为空");
			}
			Constant second = args[0];
			if(null == second || null == second.getDataValue()){
				//抛NULL异常
				throw new NullPointerException("操作符\"" + THIS_OPERATOR.getToken() + "\"参数为空");
			}
			//运算：
			//如果第一参数为引用，则执行引用
			if(first.isReference()){
				Reference firstRef = (Reference)first.getDataValue();
				first = firstRef.execute();
			}
			if(DataType.DATATYPE_BOOLEAN ==  first.getDataType()){
				//对AND操作的优化处理，first为false，则忽略计算第二参数
				if(first.getBooleanValue()){
					//如果第二参数为引用，则执行引用
					if(second.isReference()){
						Reference secondRef = (Reference)second.getDataValue();
						second = secondRef.execute();
					}
					if(DataType.DATATYPE_BOOLEAN == second.getDataType()){
						return second;
					}else{
						//抛异常
						throw new IllegalArgumentException("操作符\"" + THIS_OPERATOR.getToken() + "\"第二参数类型错误");
					}
					
				}else{
					return first;
				}
			}else {
				//抛异常
				throw new IllegalArgumentException("操作符\"" + THIS_OPERATOR.getToken() + "\"第一参数类型错误");

			}
		}

		/* (non-Javadoc)
		 * @see com.huaqin.expression.op.IOperatorExecution#verify(int, com.huaqin.expression.ExpressionToken[])
		 */
		public Constant verify(int opPositin, BaseDataMeta[] args)
				throws IllegalExpressionException {

			if(args == null){
				throw new IllegalArgumentException("运算操作符参数为空");
			}
			if(args.length != 2){
				//抛异常
				throw new IllegalExpressionException("操作符\"" + THIS_OPERATOR.getToken() + "\"参数丢失"
							, THIS_OPERATOR.getToken()
							, opPositin
						);
			}
			
			BaseDataMeta first = args[1];
			BaseDataMeta second = args[0];
			if(first == null || second == null){
				throw new NullPointerException("操作符\"" + THIS_OPERATOR.getToken() + "\"参数为空");
			}
			
			if(DataType.DATATYPE_BOOLEAN ==  first.getDataType()
					&& DataType.DATATYPE_BOOLEAN == second.getDataType()){
				
				return new Constant(DataType.DATATYPE_BOOLEAN , Boolean.FALSE);
				
			}else {
				//抛异常
				throw new IllegalExpressionException("操作符\"" + THIS_OPERATOR.getToken() + "\"参数类型错误"
						, THIS_OPERATOR.getToken()
						, opPositin
						);

			}		

		}

	}
	
	/**
	 * 逻辑或操作
	 */
	public class Op_OR implements IOperatorExecution {
		
		public static final Operator THIS_OPERATOR = Operator.OR;

		/* (non-Javadoc)
		 * @see com.huaqin.expression.op.IOperatorExecution#execute(com.huaqin.expression.ExpressionToken[])
		 */
		public Constant execute(Constant[] args) throws IllegalExpressionException {

			if(args == null || args.length != 2){
				throw new IllegalArgumentException("操作符\"" + THIS_OPERATOR.getToken() + "参数个数不匹配");
			}
			Constant first = args[1];
			if(null == first || null == first.getDataValue()){
				//抛NULL异常
				throw new NullPointerException("操作符\"" + THIS_OPERATOR.getToken() + "\"参数为空");
			}
			Constant second = args[0];
			if(null == second || null == second.getDataValue()){
				//抛NULL异常
				throw new NullPointerException("操作符\"" + THIS_OPERATOR.getToken() + "\"参数为空");
			}
			
			//运算：
			//如果第一参数为引用，则执行引用
			if(first.isReference()){
				Reference firstRef = (Reference)first.getDataValue();
				first = firstRef.execute();
			}
			if(DataType.DATATYPE_BOOLEAN ==  first.getDataType()){
				//对OR操作的优化处理，first为true，则忽略计算第二参数
				if(first.getBooleanValue()){
					return first;
				}else{
					//如果第二参数为引用，则执行引用
					if(second.isReference()){
						Reference secondRef = (Reference)second.getDataValue();
						second = secondRef.execute();
					}
					if(DataType.DATATYPE_BOOLEAN == second.getDataType()){
						return second;
					}else{
						//抛异常
						throw new IllegalArgumentException("操作符\"" + THIS_OPERATOR.getToken() + "\"第二参数类型错误");
					}
					
				}
			}else {
				//抛异常
				throw new IllegalArgumentException("操作符\"" + THIS_OPERATOR.getToken() + "\"第一参数类型错误");

			}
		}

		/* (non-Javadoc)
		 * @see com.huaqin.expression.op.IOperatorExecution#verify(int, com.huaqin.expression.ExpressionToken[])
		 */
		public Constant verify(int opPositin, BaseDataMeta[] args)
				throws IllegalExpressionException {

			if(args == null){
				throw new IllegalArgumentException("运算操作符参数为空");
			}
			if(args.length != 2){
				//抛异常
				throw new IllegalExpressionException("操作符\"" + THIS_OPERATOR.getToken() + "\"参数个数不匹配"
							, THIS_OPERATOR.getToken()
							, opPositin
						);
			}
			
			BaseDataMeta first = args[1];
			BaseDataMeta second = args[0];
			if(first == null || second == null){
				throw new NullPointerException("操作符\"" + THIS_OPERATOR.getToken() + "\"参数为空");
			}		

			if(BaseDataMeta.DataType.DATATYPE_BOOLEAN ==  first.getDataType()
					&& BaseDataMeta.DataType.DATATYPE_BOOLEAN == second.getDataType()){			
				return new Constant(BaseDataMeta.DataType.DATATYPE_BOOLEAN , Boolean.FALSE);
				
			}else {
				//抛异常
				throw new IllegalExpressionException("操作符\"" + THIS_OPERATOR.getToken() + "\"参数类型错误"
						, THIS_OPERATOR.getToken()
						, opPositin
						);

			}
		}

	}
}
